////
/// @group autocomplete
////

@use "sass:list";
@use "sass:map";
@use "sass:math";
@use "sass:string";
@use "../utils";
@use "../box/box";
@use "../button/button";
@use "../chip/chip";
@use "../icon/icon";
@use "../form/base";
@use "../form/text-field";
@use "../progress/progress";

/// Set to `true` to disable all the styles
/// @type Boolean
$disable-everything: false !default;

/// Set to `true` to disable the clear button styles
/// @type Boolean
$disable-clear-button: false !default;

/// The default behavior for the clear button is to become visible only when:
/// - the input has a value AND
/// - the user is hovering the input OR the user is focusing the input
///
/// Set this to `true` to always show the clear button unless the
/// `disableClearButton` was enabled on the `Autocomplete`.
///
/// @type Boolean
$disable-clear-button-display-none-query: false !default;

/// Set to `true` to disable the dropdown button styles
/// @type Boolean
$disable-dropdown-button: false !default;

/// Set to `true` to disable the circular progress styles
/// @type Boolean
$disable-circular-progress: false !default;

/// Set to `true` to disable setting `text-overflow: ellipsis` on the input
/// @type Boolean
$disable-text-overflow-ellipsis: false !default;

/// Set to `true` to disable the inline chip styles
/// @type Boolean
$disable-inline-chips: chip.$disable-everything !default;

/// This is the min width for the input when there are inline chips. This causes
/// the input to wrap to the next line.
/// @type Number
$inline-min-width: 5rem !default;

/// The amount of spacing between each inline chip
/// @type Number
$inline-chips-gap: icon.get-var(spacing) !default;

/// The vertical padding to apply to the text field when using inline chips and
/// the outline theme. This is used so that the chips and floating label look
/// nice.
/// @type Number
$inline-outlined-vertical-padding: calc(
  (text-field.get-var(height) - chip.get-var(height)) / 2 -
    text-field.$border-width
) !default;

/// The amount of padding to apply to the text field when there is at least one
/// chip visible. The default behavior makes it so the text in the input matches
/// with a chip if they were stacked.
///
/// @type Number
$inline-input-leading-padding: chip.get-var(horizontal-padding) !default;

/// Updates all the icon button sizes that appear within the autocomplete to use
/// this new size
/// @type Number
$button-size: button.$icon-small-size !default;

/// The size of the circular progress and used to generate the correct padding
/// for all the inline addons
/// @type Number
$circular-progress-size: button.$icon-small-size !default;

/// The amount of gap between the circular progress, clear button, and dropdown
/// button (when they exist).
///
/// @type Number
$addon-gap: text-field.$addon-gap !default;

/// The spacing between the input and the circular progress/clear button/dropdown
/// button addons.
///
/// @type Number
$addon-spacing: text-field.get-var(addon-spacing) !default;

/// The size of the clear button and used to generate the correct padding for all
/// the inline addons
/// @type Number
$clear-button-size: calc(button.get-var(icon-font-size) * 2) !default;

/// The size of the dropdown button and used to generate the correct padding for all
/// the inline addons
/// @type Number
$dropdown-button-size: calc(button.get-var(icon-font-size) * 2) !default;

/// @access private
/// @type String
$_chip-selector: ".rmd-autocomplete__chip";
/// @access private
/// @type String
$_clear-button-selector: ".rmd-autocomplete__clear-button";
/// @access private
/// @type String
$_dropdown-button-selector: ".rmd-autocomplete__dropdown-button";
/// @access private
/// @type String
$_outline-selector: ".rmd-text-field-container--outline";
/// @access private
/// @type String
$_underline-selector: ".rmd-text-field-container--underline";

// show the clear button if the autocomplete container is hovered or
// any element is focused within the container
$_clear-button-hover-selector: "&:where(:not(:hover):not(:focus-within)) :where(#{$_clear-button-selector + "--hover"})";

// stacks on top of the hover behavior, and also enforces only
// showing the clear button if the input has a value (or query)
$_clear-button-valued-selector: "&:where(:has(:placeholder-shown)) :where(#{$_clear-button-selector + "--query"})";

$_clear-button-display-none-selector: $_clear-button-hover-selector + ", "
  $_clear-button-valued-selector;

/// The available configurable css variables and mostly used internally for the
/// `get-var`, `set-var`, and `use-var` utils.
/// @type List
$variables: (
  clear-button-size,
  dropdown-button-size,
  circular-progress-size,
  inline-gap,
  inline-min-width,
  addon-gap,
  gap-count,
  addon-spacing
);

/// @param {String} name - The supported variable name
/// @param {any} fallback [null] - An optional fallback value
/// @returns {String} a `var()` statement
@function get-var($name, $fallback: null) {
  $var: utils.get-var-name($variables, $name, "autocomplete");
  @if $fallback {
    @return var(#{$var}, #{$fallback});
  }

  @return var(#{$var});
}

/// @param {String} name - The supported variable name
/// @param {any} value - The value to set the variable to. Supports `null` which
/// will just be a no-op.
@mixin set-var($name, $value) {
  @if $value {
    #{utils.get-var-name($variables, $name, "autocomplete")}: #{$value};
  }
}

/// @param {String} property - The css property to apply the variable to
/// @param {String} name [$property] - The supported variable name
/// @param {any} fallback [null] - An optional fallback value if the variable
/// has not been set
@mixin use-var($property, $name: $property, $fallback: null) {
  #{$property}: get-var($name, $fallback);
}

/// Conditionally applies the css variables based on feature flags
@mixin variables {
  @if not $disable-everything {
    @include set-var(addon-gap, $addon-gap);
    @include set-var(addon-spacing, $addon-spacing);
    @if not $disable-inline-chips {
      @include set-var(inline-gap, $inline-chips-gap);
      @include set-var(inline-min-width, $inline-min-width);
    }
  }
}

/// Used to create a `calc` expression for the right addons.
///
/// @access private
/// @returns {String} A `calc` string
@function _right-addon-calc() {
  $calc-spacing: get-var(addon-spacing);
  $calc-total-gap: calc(get-var(gap-count, 0) * get-var(addon-gap));
  $calc-clear-button: if(
    $disable-clear-button,
    "",
    " + " + get-var(clear-button-size, 0px)
  );
  $calc-dropdown-button: if(
    $disable-dropdown-button,
    "",
    " + " + get-var(dropdown-button-size, 0px)
  );
  $calc-circular-progress: if(
    $disable-circular-progress,
    "",
    " + " + get-var(circular-progress-size, 0px)
  );
  $calc-addon-size: $calc-clear-button + $calc-dropdown-button +
    $calc-circular-progress;

  @return calc($calc-spacing + #{$calc-total-gap + $calc-addon-size});
}

/// Used to create a `:has` selector for the different addons.
///
/// @access private
/// @param {String} appending-selector
/// @param {String} addon-selector
/// @returns {String} a class name selector
@function _add-has-selector($appending-selector, $addon-selector) {
  $prefix: if(string.length($appending-selector), "", "&");

  @return $appending-selector + $prefix + ":has(" + $addon-selector + ")";
}

/// Generates all the styles for the `Autocomplete` components based on feature
/// flags.
///
/// @param {Boolean} disable-layer [false] - Set this to `true` to disable the
/// layer behavior
@mixin styles($disable-layer: false) {
  // disclaimer: this is the first component where I'm trying to utilize more of
  // the `:has`, `:where`, `:is`, etc selectors to require less javascript and
  // move more behavior into CSS

  @if not $disable-everything {
    @include utils.optional-layer(autocomplete, $disable-layer) {
      .rmd-autocomplete {
        @if not $disable-clear-button and not $disable-dropdown-button {
          @include button.set-var(icon-font-size, $button-size);
        }
        @if not $disable-circular-progress {
          @include progress.set-var(circular-size, $circular-progress-size);
        }

        @if not
          $disable-clear-button or not
          $disable-dropdown-button or not
          $disable-circular-progress
        {
          // the way the padding right works is to create a calc string that
          // sums all the available addons widths (including gap) that have
          // been rendered in the autocomplete. to calculate the gap, the
          // `&--db` and `&--cp` selectors will increase the `gap-count`
          // variable based on how many other addons exist with it.
          //
          // So:
          // - only clear button - count == 0
          // - only dropdown button - count == 0
          // - only circular progress - count == 0
          // - clear button and dropdown button - count == 1
          // - clear button and circular progress - count == 1
          // - dropdown button and circular progress - count == 1
          // - circular progress, clear button, and dropdown button - count == 2
          //
          // When the addon isn't included, its size will be set to `0px`. When
          // the addon is included, the size is set to the correct value
          @include text-field.set-var(padding-right, _right-addon-calc());
        }

        @if not $disable-text-overflow-ellipsis {
          &:where(:not(:hover):not(:focus-within)) :where(.rmd-text-field) {
            text-overflow: ellipsis;
          }
        }

        @if not $disable-clear-button {
          &--cb {
            @include set-var(clear-button-size, $clear-button-size);
          }
        }

        @if not $disable-dropdown-button {
          &--db {
            @include set-var(dropdown-button-size, $dropdown-button-size);

            @if not $disable-clear-button {
              &:has(#{$_clear-button-selector}) {
                @include set-var(gap-count, 1);
              }
            }
          }
        }

        @if not $disable-circular-progress {
          &--cp {
            @include set-var(circular-progress-size, $circular-progress-size);

            $two-addon-selector: "";
            $single-selector-list: ();
            @if not $disable-clear-button {
              $single-selector-list: list.append(
                $single-selector-list,
                $_clear-button-selector,
                $separator: comma
              );
              $two-addon-selector: _add-has-selector(
                $two-addon-selector,
                $_clear-button-selector
              );
            }

            @if not $disable-dropdown-button {
              $single-selector-list: list.append(
                $single-selector-list,
                $_dropdown-button-selector,
                $separator: comma
              );
              $two-addon-selector: _add-has-selector(
                $two-addon-selector,
                $_dropdown-button-selector
              );
            }

            @if list.length($single-selector-list) {
              &:has(#{$single-selector-list}) {
                @include set-var(gap-count, 1);
              }
            }
            @if string.length($two-addon-selector) {
              #{$two-addon-selector} {
                @include set-var(gap-count, 2);
              }
            }
          }
        }

        @if not
          $disable-clear-button and not
          $disable-clear-button-display-none-query
        {
          #{$_clear-button-display-none-selector} {
            display: none;
          }
        }

        @if not $disable-inline-chips {
          // the basic idea for the inline chips are:
          // - move any padding from the input to the container element
          // - update the styles to display a text cursor when hovering the
          //   container element instead of only the input (since clicking
          //   anywhere in the container focuses the input)
          // - keep other styles the same until at least one chip exists
          // - when a chip exists, update the vertical padding to align
          //   everything nicely
          // - the input will also be updated to align with the text of a chip
          //   so it looks nicely when stacked and starting at the beginning of
          //   a line
          // - I am NOT updating the underline behavior to match the input width
          //   since those are still "boxed" elements and it helps show current
          //   focus
          &--inline-chips {
            @include text-field.use-var(min-height, height);
            @include text-field.use-var(padding-right);
            @include use-var(gap, inline-gap);

            flex-wrap: wrap;
            height: auto;

            &:where(:not(:has(.rmd-text-field:disabled))) {
              cursor: text;
            }

            @if not
              base.$form-disable-filled-theme or not
              base.$form-disable-underlined-theme
            {
              &:where(#{$_underline-selector}):has(#{$_chip-selector}) {
                @include text-field.use-var(padding-top);
                @include use-var(padding-bottom, inline-gap);

                :where(.rmd-text-field) {
                  padding-top: 0;
                }
              }
            }

            @if not base.$form-disable-outlined-theme {
              &:where(#{$_outline-selector}):has(#{$_chip-selector}) {
                padding-bottom: $inline-outlined-vertical-padding;
                padding-top: $inline-outlined-vertical-padding;
              }
            }

            &:has(#{$_chip-selector}) {
              // when at least one chip exists, ensure the text field has some
              // leading padding and always display the placeholder (if exists)
              // since the label will also be forced to floating
              :where(.rmd-text-field) {
                @include use-var(min-width, inline-min-width);
                @include chip.use-var(height);

                padding-left: $inline-input-leading-padding;
                padding-right: 0;
                width: 0;

                &::placeholder {
                  opacity: 1;
                }

                @include utils.rtl {
                  padding-left: 0;
                  padding-right: $inline-input-leading-padding;
                }
              }
            }

            @include utils.rtl {
              @include text-field.use-var(padding-left, padding-right);

              padding-right: 0;
            }
          }
        }

        &__right-addon {
          padding-left: get-var(addon-spacing);
          right: 0;

          @include utils.rtl {
            left: 0;
            padding-left: 0;
            padding-right: get-var(addon-spacing);
            right: auto;
          }
        }
      }
    }
  }
}
